package xcmg.device.service.wechat;

import com.github.pagehelper.PageInfo;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import xcmg.device.dao.entity.DataDictionaryDO;
import xcmg.device.dao.entity.area.DealerStorefrontDO;
import xcmg.device.dao.entity.basic.SystemParameter;
import xcmg.device.dao.entity.company.CompanyDealerDO;
import xcmg.device.dao.entity.setting.WeChatConfigDO;
import xcmg.device.dao.entity.wechat.xgwj.WechatRelatedAttachment;
import xcmg.device.dao.mapper.CompanyDealerMapper;
import xcmg.device.dao.mapper.DataDictionaryMapper;
import xcmg.device.dao.mapper.DealerStorefrontMapper;
import xcmg.device.dao.mapper.WeChatConfigMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInventoryMapper;
import xcmg.device.dao.mapper.wechat.xgwj.MaterialsGuidePriceMapper;
import xcmg.device.dao.mapper.wechat.xgwj.WechatRelatedAttachmentMapper;
import xcmg.device.infra.FileUtil;
import xcmg.device.infra.HttpRequestUtil;
import xcmg.device.infra.LocationUtil;
import xcmg.device.infra.SignWechat;
import xcmg.device.service.MaterialClassService;
import xcmg.device.service.basic.SystemParameterService;
import xcmg.device.service.vo.MaterialClassVO;
import xcmg.device.service.vo.setting.GuidePriceResultVO;
import xcmg.device.service.vo.wechat.DealerStorefrontVO;
import xcmg.device.service.vo.wechat.DocumentCategoryVO;
import xcmg.device.service.vo.wechat.MaterialsInfoSearchVO;
import xcmg.device.service.vo.wechat.MaterialsInventoryVO;
import xcmg.device.service.vo.wechat.StoreSearchParam;
import xcmg.device.service.warehouse.CommonService;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class WechatService {

    @Autowired
    private WeChatConfigMapper weChatConfigMapper;

    @Autowired
    private DealerStorefrontMapper dealerStorefrontMapper;

    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;

    @Autowired
    private CompanyDealerMapper CompanyDealerDO;

    @Autowired
    private DataDictionaryMapper dataDictionaryMapper;

    @Autowired
    private MaterialsGuidePriceMapper materialsGuidePriceMapper;

    @Autowired
    private SystemParameterService systemParameterService;

    @Autowired
    private WechatRelatedAttachmentMapper wechatRelatedAttachmentMapper;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private CommonService commonService;

  @Autowired
  private HttpServletResponse response;

  @Autowired
  private MaterialClassService materialClassService;
  /**
   * 微信端资料说明的分类参数名
   */
  private static final String WECHAT_DOCUMENT_FILE_CATEGORYS_TYPE = "WECHAT_DOCUMENT_CATEGORYS";


  @Value("${spring.file.download.path}")
  private String filePath;

  private static final String FILE_UPLOAD_PATH = "wechat_document_attach/";

  /**
   * 数据字典中，微信端代理商距离ParentCode为'AGENT_DISTANCE',备件查询功能代理商范围CODE为1，附近代理商距离CODE为2
   */
  private static final String AGENT_DISTANCE_PARENT_CODE = "AGENT_DISTANCE", BJ_SEARCH_DISTANCE_CODE = "1", AGENT_DISTANCE_CODE = "2";

    final Base64.Decoder decoder = Base64.getDecoder();
    final Base64.Encoder encoder = Base64.getEncoder();

    public Map<String, String> getSignData(String signUrl) throws JSONException {

        WeChatConfigDO configDO=weChatConfigMapper.item();
        if(configDO==null){
            return null;
        }
        String ticket="";
        if(configDO.getUpdateTime()!=null){
            long ms=(System.currentTimeMillis()-configDO.getUpdateTime().getTime())/1000;
            if(ms<7000){
                ticket=configDO.getTicket();
            }
        }
        if(ticket==""){
            String url="https://api.weixin.qq.com/cgi-bin/token";
            String param="grant_type=client_credential&appid="+configDO.getAppId()+"&secret="+configDO.getSecretId();
            String resultToken= HttpRequestUtil.sendGet(url,param);

            JSONObject jObject1=new JSONObject(resultToken);
            String token= jObject1.getString("access_token");

            String tickUrl="http://api.weixin.qq.com/cgi-bin/ticket/getticket";
            String tickParm="type=jsapi&access_token="+token;
            String resultTick= HttpRequestUtil.sendGet(tickUrl,tickParm);
            JSONObject jObject2=new JSONObject(resultTick);
            ticket=jObject2.getString("ticket");
            configDO.setTicket(ticket);
            configDO.setToken(token);
            configDO.setUpdateTime(new Date());
            weChatConfigMapper.update(configDO);
        }

        Map<String, String> result= SignWechat.sign(ticket,signUrl);
        result.put("appId",configDO.getAppId());
        return result;
    }


    /**
     * 用户输入机型时去首尾空格并且转大写（忽略用户输入的大小写），提升用户体验
     *
     * @param str
     * @return
     */
    private String formatSearchStr(String str) {
        if (StringUtils.isBlank(str)) {
            return StringUtils.EMPTY;
        }
        return str.trim().toUpperCase();
    }

    public List<DealerStorefrontVO> getNearbyStore(double longitude, double latitude){
        WeChatConfigDO configDO=weChatConfigMapper.item();
        if(configDO==null){
            return new ArrayList<>();
        }

      List<DealerStorefrontDO> doList = dealerStorefrontMapper
          .list(fillStoreSearchParam(configDO.getOrgId(), latitude, longitude, AGENT_DISTANCE_CODE));
        List<DealerStorefrontVO> voList=new ArrayList<>();
        for (DealerStorefrontDO dealerStorefrontDO:doList
             ) {
            DealerStorefrontVO dealerStorefrontVO=new DealerStorefrontVO();
            BeanUtils.copyProperties(dealerStorefrontDO,dealerStorefrontVO);
            double distance=LocationUtil.getDistance(latitude,longitude,dealerStorefrontVO.getLatitude().doubleValue(),dealerStorefrontVO.getLongitude().doubleValue());
            dealerStorefrontVO.setDistance(Math.round(distance));
            voList.add(dealerStorefrontVO);
        }

        sortByDistance(voList);
        return voList;
    }

    public List<DealerStorefrontVO> getStorefrontByArea(StoreSearchParam storeSearchParam){
        WeChatConfigDO configDO=weChatConfigMapper.item();
        if(configDO==null){
            return new ArrayList<>();
        }
        storeSearchParam.setOrgId(configDO.getOrgId());
        storeSearchParam.setIsEnable(1);
        List<DealerStorefrontDO> doList=dealerStorefrontMapper.list(storeSearchParam);
        List<DealerStorefrontVO> voList=new ArrayList<>();
        for (DealerStorefrontDO dealerStorefrontDO:doList
                ) {
            DealerStorefrontVO dealerStorefrontVO=new DealerStorefrontVO();
            BeanUtils.copyProperties(dealerStorefrontDO,dealerStorefrontVO);
            voList.add(dealerStorefrontVO);
        }
        return voList;
    }

  /**
   * 填充距离计算相关信息
   *
   * @param orgId
   * @param latitude
   * @param longitude
   * @return
   */
  private StoreSearchParam fillStoreSearchParam(String orgId, double latitude, double longitude, String agentDistanceCode) {
    //地球半径千米
    double r = 6371;

    DataDictionaryDO dictionaryDO = dataDictionaryMapper.itemByCode(AGENT_DISTANCE_PARENT_CODE, agentDistanceCode);
    double dis = Double.valueOf(dictionaryDO.getName());
    //角度转为弧度
    double dlng = 2 * Math.asin(Math.sin(dis / (2 * r)) / Math.cos(Math.PI / 180 * latitude));
    dlng = dlng * 180 / Math.PI;
    double dlat = dis / r;
    dlat = dlat * 180 / Math.PI;
    double minlat = latitude - dlat;
    double maxlat = latitude + dlat;
    double minlng = longitude - dlng;
    double maxlng = longitude + dlng;

    StoreSearchParam storeSearchParam = new StoreSearchParam();
    storeSearchParam.setOrgId(orgId);
    storeSearchParam.setIsEnable(1);
    storeSearchParam.setMinlat(minlat);
    storeSearchParam.setMaxlat(maxlat);
    storeSearchParam.setMinlng(minlng);
    storeSearchParam.setMaxlng(maxlng);
    return storeSearchParam;
  }


  /**
   * 第一步获取有该零件的附近的代理商相关信息
   *
   * @param searchVO
   * @return
   */
  public List<DealerStorefrontVO> materialsSearch(MaterialsInfoSearchVO searchVO) {
    if (StringUtils.isBlank(searchVO.getMaterialsDes()) && StringUtils
        .isBlank(searchVO.getMachineType())) {
      return new ArrayList<>();
    }
    WeChatConfigDO configDO = weChatConfigMapper.item();
    if (configDO == null) {
      return new ArrayList<>();
    }
    double latitude = searchVO.getLatitude();
    double longitude = searchVO.getLongitude();
    List<DealerStorefrontDO> doList = dealerStorefrontMapper
        .list(fillStoreSearchParam(configDO.getOrgId(), latitude, longitude, BJ_SEARCH_DISTANCE_CODE));
    List<DealerStorefrontVO> voList = new ArrayList<>();

    for (DealerStorefrontDO dealerStorefrontDO : doList) {
      DealerStorefrontVO dealerStorefrontVO = new DealerStorefrontVO();
      BeanUtils.copyProperties(dealerStorefrontDO, dealerStorefrontVO);
      double distance = LocationUtil
          .getDistance(latitude, longitude, dealerStorefrontVO.getLatitude().doubleValue(),
              dealerStorefrontVO.getLongitude().doubleValue());
      dealerStorefrontVO.setDistance(Math.round(distance));
      CompanyDealerDO companyDealerDO = CompanyDealerDO
          .itemByOrgId(configDO.getOrgId(), dealerStorefrontDO.getDealerOrgId());
      if (null == companyDealerDO) {
        continue;
      }
      dealerStorefrontVO.setPlatOrgId(companyDealerDO.getPlatOrgId());
      dealerStorefrontVO.setPlatCompany(companyDealerDO.getIsPlatCompany());

      if (companyDealerDO != null && companyDealerDO.getIsPlatCompany()) {
        Integer materialsCount = warehouseInventoryMapper
            .countCompanyMaterials(companyDealerDO.getPlatOrgId(),
                StringUtils.trim(searchVO.getMaterialsDes()),
                formatSearchStr(searchVO.getMachineType()));
        if (null == materialsCount || materialsCount <= 0) {
          continue;
        }
        voList.add(dealerStorefrontVO);
      }
    }

    sortByDistance(voList);
    return voList;
  }


  /**
   * 按距离排序
   *
   * @param list
   */
  private void sortByDistance(List<DealerStorefrontVO> list) {
    Collections.sort(list, (o1, o2) -> {
      if (o1.getDistance() > o2.getDistance()) {
        return 1;
      }
      return -1;
    });
  }

  /**
   * 第二步获取代理商零件库存信息
   *
   * @param condition
   * @return
   */
  public PageCommonVO listMaterialsByCompany(SearchCommonVO<MaterialsInfoSearchVO> condition ) {
    MaterialsInfoSearchVO searchVO = condition.getFilters();
    PageCommonVO result = new PageCommonVO();
    if (!searchVO.isPlatCompany()) {
      result.setPageInfo(new PageInfo(new ArrayList()));
      result.setPageInfoList(new ArrayList());
      return result;
    }
      PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
    List<MaterialsInventoryVO> storefrontVOS = warehouseInventoryMapper
        .companyInventory(searchVO.getPlatOrgId(), StringUtils.trim(searchVO.getMaterialsDes()),
            formatSearchStr(searchVO.getMachineType()));

    result.setPageInfo(new PageInfo(storefrontVOS));
    result.setPageInfoList(storefrontVOS);
    return result;
  }


  /**
   * 备件指导价查询
   *
   * @param condition
   * @return
   */
  public PageCommonVO guidePriceQuery(SearchCommonVO<MaterialsInfoSearchVO> condition){
    MaterialsInfoSearchVO searchVO = condition.getFilters();
    PageCommonVO result = new PageCommonVO();
    WeChatConfigDO configDO=weChatConfigMapper.item();
    if(configDO==null){
      result.setPageInfo(new PageInfo(new ArrayList()));
      result.setPageInfoList(new ArrayList());
      return result;
    }
    if (StringUtils.isBlank(searchVO.getMaterialsDes()) && StringUtils
        .isBlank(searchVO.getMaterialsNo()) && StringUtils
        .isBlank(searchVO.getMachineType())  && StringUtils
            .isBlank(searchVO.getClassValue())) {
      result.setPageInfo(new PageInfo(new ArrayList()));
      result.setPageInfoList(new ArrayList());
      return result;
    }
      PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
    List <GuidePriceResultVO> resultVOS = materialsGuidePriceMapper
        .listByMaterialsNo(configDO.getOrgId(), StringUtils.trim(searchVO.getMaterialsDes()),
            formatSearchStr(searchVO.getMachineType()),
            StringUtils.trim(searchVO.getMaterialsNo()),searchVO.getClassValue());
    result.setPageInfo(new PageInfo(resultVOS));
    result.setPageInfoList(resultVOS);
    return result;
  }

  public List<DocumentCategoryVO> listFileCategorys() {
    List<DocumentCategoryVO> categoryVOS = new ArrayList<>();
    List<SystemParameter> parameters = systemParameterService.listByParamType(WECHAT_DOCUMENT_FILE_CATEGORYS_TYPE);
    if (CollectionUtils.isEmpty(parameters)) {
      return categoryVOS;
    }
    DocumentCategoryVO categoryVO;
    for (SystemParameter parameter : parameters) {
      categoryVO = new DocumentCategoryVO();
      categoryVO.setCategoryType(parameter.getParamKey());
      categoryVO.setCategoryName(parameter.getParamValue());
      categoryVOS.add(categoryVO);
    }
    return categoryVOS;
  }
  public List<MaterialClassVO> materialClassList(MaterialClassVO materialClassVO) {
      WeChatConfigDO configDO=weChatConfigMapper.item();
      if(configDO==null){
          return new ArrayList<>();
      }
      materialClassVO.setOrgId(configDO.getOrgId());
      return materialClassService.list(materialClassVO);
  }

  public List<WechatRelatedAttachment> listAttachmentsByType(Short type) throws UnsupportedEncodingException {
      List<WechatRelatedAttachment> wechatRelatedAttachments = wechatRelatedAttachmentMapper.listByType(type);
      for (WechatRelatedAttachment wechatRelatedAttachment: wechatRelatedAttachments) {
          String fileName = wechatRelatedAttachment.getFileName();
          wechatRelatedAttachment.setFileName(new String(decoder.decode(fileName), "utf-8"));
      }
      return wechatRelatedAttachments;
  }

  @Transactional(rollbackFor = Exception.class)
  public void batchSave(List<MultipartFile> files, Short fileType, String userId, String orgId) throws Exception {
    if (CollectionUtils.isEmpty(files)) {
      throw new Exception("请上传附件");
    }
    if (files.size() >= 10)  {
      throw new Exception("单次上传数量必须小于10");
    }
    SystemParameter systemParameter = systemParameterService.getByParamKey(WECHAT_DOCUMENT_FILE_CATEGORYS_TYPE, fileType);
    if (null == systemParameter) {
      throw new Exception("文档分类信息不存在");
    }
    WechatRelatedAttachment attachment4DB;
    for (MultipartFile file : files) {
      attachment4DB = uploadFile(file, fileType, systemParameter.getParamValue(), userId, orgId);
      wechatRelatedAttachmentMapper.insert(attachment4DB);
    }
  }

  private WechatRelatedAttachment uploadFile(MultipartFile file, Short fileType, String typeDesc, String userId, String orgId) throws Exception {
    WechatRelatedAttachment attachment = new WechatRelatedAttachment();
    ActionResult<String> textResult = fastGenClient.textGuid();
    String fileSysId = textResult.getValue();
    String sysFileName;
    try {
      sysFileName = fileSysId + file.getOriginalFilename()
          .substring(file.getOriginalFilename().lastIndexOf("."));
      FileUtil.uploadFile(file, getFilePath(), sysFileName);
      attachment.setId(fileSysId);
      attachment.setFileType(fileType);
      attachment.setTypeDesc(typeDesc);
      LogHelper.monitor("originalFilename" + file.getOriginalFilename());
      String fileName = encoder.encodeToString(file.getOriginalFilename().getBytes("utf-8"));
      attachment.setFileName(fileName);
      attachment.setSysFileName(sysFileName);
      attachment.setOrgId(orgId);
      attachment.setCreateId(userId);
      attachment.setCreateName(commonService.getUserName(userId));
      attachment.setCreateTime(new Date());
    } catch (Exception e) {
      LogHelper.fatal("WechatService#uploadFile is error.", e);
      throw new Exception(e);
    }
    return attachment;
  }

  private String getFilePath() {
    return filePath + FILE_UPLOAD_PATH;
  }

  /**
   * 删除单个文件
   */
  @Transactional(rollbackFor = Exception.class)
  public void deleteAttachment(String attachId) throws Exception {
    WechatRelatedAttachment attachment = wechatRelatedAttachmentMapper.getById(attachId);
    if (null == attachment) {
      throw new Exception("文件不存在");
    }

    FileUtil.deleteFile(getFilePath(), attachment.getSysFileName());
    wechatRelatedAttachmentMapper.deleteById(attachId);
  }


  /**
   * 单个下载附件
   */
  public void downloadAttach(String attachId) throws Exception {
    WechatRelatedAttachment attachment = wechatRelatedAttachmentMapper.getById(attachId);
    FileUtil .downLoadFileUseOldName(response, getFilePath(), attachment.getSysFileName(), new String(decoder.decode(attachment.getFileName()), "utf-8"));
  }

}